package com.example.aop.aspect;

import com.example.common.Statistical;
import com.example.common.utils.Statistics;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Slf4j
@Component
@Aspect
public class MyAspect implements Statistical {

    private int order;

    private MyAspect() {
        Statistics.logInfo(log);
    }

    @Override
    public synchronized int gas(){
        return order++;
    }

    @Pointcut("@annotation(com.example.aop.anno.MyAnno)")
    public void pointCut() {
        //pointCut方法必须为空
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Statistics.logInfo(log, this, "around", toStringJoinPoint(joinPoint));
        Object object = joinPoint.proceed();
        Statistics.logInfo(log, this, "around", object);
        return object;
    }

    @Before(value = "pointCut()")
    public void before(JoinPoint joinPoint) {
        Statistics.logInfo(log, this, "before", toStringJoinPoint(joinPoint));
    }

    @AfterReturning(pointcut = "pointCut()", returning = "returning")
    public void afterReturning(JoinPoint joinPoint, Object returning) {
        Statistics.logInfo(log, this, "afterReturning", returning);
    }

    @After("pointCut()")
    public void after(JoinPoint joinPoint) {
        Statistics.logInfo(log, this, "after", toStringJoinPoint(joinPoint));
    }

    @AfterThrowing(pointcut = "pointCut()", throwing = "throwing")
    public void afterThrowing(JoinPoint joinPoint, Throwable throwing) {
        Statistics.logInfo(log, this, "afterThrowing", throwing);
    }

    private static String toStringJoinPoint(JoinPoint joinPoint) {
        return "\n\targs : " + Arrays.toString(joinPoint.getArgs()) +
                "\n\tkind : " + joinPoint.getKind() +
                "\n\tmethod : " + joinPoint.getSignature().getName() +
                "\n\tclass : " + joinPoint.getSignature().getDeclaringTypeName() +
                "\n\ttarget : " + joinPoint.getTarget();
    }
}
